﻿using FarseerGames.FarseerPhysics;
using FarseerGames.FarseerPhysics.Collisions;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Factories;
using UnitLibrary.DrawingSystem;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using UnitLibrary.Managers;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Content;
using UnitLibrary;
using UnitLibrary.GameObjects.Units;
using FarseerGames.FarseerPhysics.Mathematics;


namespace UnitLibrary.GameObjects.Physics
{
    //todo: come up with better name
    /// <summary>
    /// A generic physics object which can be loaded in different ways
    /// </summary>
    /// 
    
    public class PhyObj: IGameObject
    {
        /// <summary>
        /// 
        /// </summary>
        public PhyObj()
        {
            _body = new Body();
            _geom = new Geom();
            _sensorGeom = new Geom();
            _isCreated = false;
            _body.MomentOfInertia = float.MaxValue;
        }
        /// <summary>
        /// Is there a reference of this physics object already in the physics simulator?
        /// </summary>
        protected bool IsRefInPhysics = false;
        protected bool IsSensorRefInPhysics = false;
        [ContentSerializerIgnore]
        protected ComponentM _components;
        public string PhyObjName = "default";
        #region Physics Generics
        public ObjectShape po_Object_Shape = ObjectShape.Circle;
        public string po_TextureName = "default";
        public Color po_IColor = Color.Black;
        public Color po_BorderColor = Color.White;
        public Color po_SensorColor = Color.HotPink;
        public Color po_SensorBorderColor = Color.Black;
        public int po_Radius = 10;
        public int po_SensorRadius = 20;
        public int po_Width = 10;
        public int po_Height = 10;
        #endregion

        #region Farseer Phy Obj Properties

        /// <summary>
        /// protectedly held physics simulator for use
        /// </summary>
        /// 
        [XmlIgnore]
        private PhysicsSimulator _physicsSimulator;
        /// <summary>
        /// The BODY of this physics object
        /// </summary>
        protected Body _body;

        /// <summary>
        /// The GEOMETRY of this physics object
        /// </summary>
       protected Geom _geom;

        /// <summary>
        /// The geometry of this object which will be used as a sensor
        /// A sensor is a geom in which collisions don't happen, but will still
        /// fire the oncollision event, perfect for use when detecting of an object is
        /// within range of another object for firing projectiles at one another
        /// </summary>
        protected Geom _sensorGeom;

        /// <summary>
        /// Used exclusively for ReLoad and Load functions.
        /// Set to true if the object has been loaded
        /// </summary>
        private bool _isCreated = false;
        
        public bool IsSensorEnabled = false;

        /// <summary>
        /// Returns the physics simulator to which this object belongs
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public PhysicsSimulator PhysicsSimulator
        {
            get { return _physicsSimulator; }
        }

        /// <summary>
        /// GET BODY
        /// </summary>
        public Body BODY
        {
            get { return _body; }
        }

        /// <summary>
        /// ADD ONCOLLISION EVENTS FOR OBJECT
        /// </summary>
        [ContentSerializerIgnore]
        public CollisionEventHandler ObjectOnCollision
        {
            set { _geom.OnCollision += value; }
            get { return _geom.OnCollision; } 
        }

        /// <summary>
        /// ADD ONCOLLISION EVENTS FOR SENSOR
        /// </summary>
        [ContentSerializerIgnore]
        public CollisionEventHandler SensorOnCollision
        {
            set { _sensorGeom.OnCollision += value; }
        }

        /// <summary>
        /// GET GEOM OF OBJECT
        /// </summary>
        public Geom GEOM
        {
            get { return _geom; }
        }

        public Geom SensorGeom
        {
            get { return _sensorGeom; }
        }

        /// <summary>
        /// GET TEXTURE OF OBJECT
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public Texture2D Texture
        {
            get { return _texture; }
        }

        /// <summary>
        /// Get Sensor texture of object
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public Texture2D SensorTexture
        {
            get { return _sensorTexture; }
        }
        /// <summary>
        /// GET COLLISIONCATEGORY OF OBJECT
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public CollisionCategory G_CollisionCategory
        {
            get { return _geom.CollisionCategories; }            
        }

        /// <summary>
        /// Get CollisionCategory of the Sensor of this object
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public CollisionCategory SensorCollisionCategory
        {
            get { return _sensorGeom.CollisionCategories; }
        }

        /// <summary>
        /// GET COLLISION CATEGORY OF COLLIDES WITH OF OBJECT
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public CollisionCategory G_CollidesWith
        {
            get { return _geom.CollidesWith; }            
        }

        /// <summary>
        /// Get Collision category of collideswith of sensor
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public CollisionCategory SensorCollidesWith
        {
            get { return _sensorGeom.CollidesWith; }
        }

        #endregion

        #region PhyObj Properties

        /// <summary>
        /// The TEXTURE of this physics object
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        protected Texture2D _texture;

        /// <summary>
        /// The texture used to draw this physics object sensor
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        protected Texture2D _sensorTexture;

        /// <summary>
        /// The ORIGIN
        /// The origin is the absolute center of the object
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        protected Vector2 _origin;

        /// <summary>
        /// The origin of the sensor for this object
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        protected Vector2 _sensorOrigin;

        /// <summary>
        /// Boolean used to determine whether or not the object is currently sensing for another object within range
        /// </summary>
        protected bool _isSensing = false;

       

       

        /// <summary>
        /// Return whether or not the object is sensing for another object around it
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public bool IsSensing
        {
            get { return _isSensing; }
        }

        
        #endregion

        #region Movement
        private Vector2 _originalSpawnLocation;
        public double MovementUpdateDelay = 40;
        protected double MovementUpdateDelayTimer = 0;
        /// <summary>
        /// Private value to determine which way to move the object
        /// There are two primary ways: by impulse and by force
        /// Default way is by applied force every frame
        /// </summary>
        private bool _isMoveByForce = true;
        /// <summary>
        /// Internal Value to determine if it is movable
        /// Used for the Move() function
        /// </summary>
        protected bool _updateMovement = true;

        protected Vector2 _moveDirection = Vector2.Zero;

        protected float _moveSpeed = 20;

        [ContentSerializerIgnore]
        /// <summary>
        /// Used for the Move() function
        /// Used during run-time
        /// Default = true
        /// </summary>
        public bool UpdateMovement
        {
            get { return _updateMovement; }
            set
            {
                //if the body is static, then this is implicitly unmovable, so keep it disabled
                if (!_body.IsStatic)
                    _updateMovement = false;
                //Otherwise this object can be movable or not depending on gameplay

                else
                    _updateMovement = value;
            }
        }

        /// <summary>
        /// Move the object by force or by impulse
        /// </summary>
        public bool IsMoveByForce
        {
            get { return _isMoveByForce; }
            set
            {
                _isMoveByForce = value;
            }
        }

        /// <summary>
        /// Gets or Sets the movespeed multiplier
        /// </summary>
        public float MoveSpeed
        {
            get { return _moveSpeed; }
            set { _moveSpeed = value; }
        }

        /// <summary>
        /// Set the Vector of which this object will move
        /// </summary>
        /// <remarks>This function is to be assumed that the position is already set</remarks>
        ///<param name="moveTo">The location where the object will move to</param>
        public void SetMoveDirection(Vector2 moveTo)
        {
            _moveDirection = moveTo - _body.Position;
            _moveDirection.Normalize();
        }

        /// <summary>
        /// Set the vector of which this object will move to
        /// </summary>
        /// <param name="newPosition">The new position of this object</param>
        /// <param name="moveTo">The position of which the object will move to</param>
        public void SetMoveDirection(Vector2 newPosition, Vector2 moveTo)
        {
            _body.Position = newPosition;
            _moveDirection = newPosition - moveTo;
            _moveDirection.Normalize();
        }

        /// <summary>
        /// A vector2 used to determine exactly which way the object is going
        /// Used when the bullet is non tracking type, it will follow along this
        /// vector2 until it is disposed
        /// </summary>
        [ContentSerializerIgnore]
        public Vector2 MoveDirection
        {
            get { return _moveDirection; }
            set { _moveDirection = value;
            if (value.Length() > 1f)
                _moveDirection.Normalize();            
            }
        }

        /// <summary>
        /// Get the movement in x coordinate
        /// </summary>
        public float MoveDirectionX
        {
            get { return _moveDirection.X; }
        }

        /// <summary>
        /// Get the move direction y coordinate
        /// </summary>
        public float MoveDirectionY
        {
            get { return _moveDirection.Y; }
        }

        /// <summary>
        /// Reset the movement direction to the current linear velocity direction
        /// </summary>
        protected void UpdateMovementDirection()
        {
            _moveDirection = _body.LinearVelocity;
            _moveDirection.Normalize();
        }

        public float DistanceFromSpawn()
        {
            return Vector2.Distance(_originalSpawnLocation, this.Position);
        }

        /// <summary>
        /// Private move function, called by the public update function
        /// </summary>
        public void Move()
        {
            if(_isMoveByForce)
                _body.ApplyForce(_moveDirection * _moveSpeed * _body.Mass);
            else
                _body.ApplyImpulse(_moveDirection * _moveSpeed );//* (_body.Mass / _moveSpeed));
        }

        #endregion

        #region PhyObj Methods

        /// <summary>
        /// 
        /// </summary>
        public void ResetDynamics()
        {
            _body.ResetDynamics();
        }

        #endregion

        #region IGameObject
        private Iid _id;
        [ContentSerializerIgnore]
        public Iid ID
        {
            get { return _id; }
            set 
            {
                    _id = value;
            }
        }

        public virtual void Update(GameTime gametime)
        {
            MovementUpdateDelayTimer += gametime.ElapsedGameTime.Milliseconds;
            if (_updateMovement)
                if (MovementUpdateDelayTimer > MovementUpdateDelay)
                {
                    Move();
                    MovementUpdateDelayTimer = 0;
                }
                else if (!_body.Moves)
                    Move();
        }

        /// <summary>
        /// Function to draw the physics object
        /// </summary>
        /// <param name="spriteBatch"></param>
        public virtual void Draw(SpriteBatch spriteBatch)
        { 
            spriteBatch.Draw(_texture, _body.Position, null, po_IColor, Calculator.VectorToRadians( this._moveDirection), _origin, 1f, SpriteEffects.None, 0f);
            if(IsSensorEnabled)
            
                spriteBatch.Draw(_sensorTexture, _body.Position, null, po_SensorColor, _body.Rotation, _sensorOrigin, 1f, SpriteEffects.None, 1f);
        }

        /// <summary>
        /// Do a deep copy of the geom and body from existing into this one
        /// </summary>
        /// <param name="existingPhyObj"></param>
        public virtual void Create(object existingPhyObj, ComponentM components, Vector2 location, Vector2 direction, bool AddToPhysics)
        {
            if (_components == null)
                _components = components;
            //If it's already loaded, no need to re deference the physics simulator
            if (!_isCreated)
            {
                _physicsSimulator = components.physicsSimulator;
            }
            PhyObj ephyobj = (PhyObj)existingPhyObj;
            //If it's not the same physics object name, we have to reload it
            if (!_isCreated)
            //if ((ephyobj.PhyObjName != this.PhyObjName) && (this._geom != ephyobj.GEOM) && (this._body != ephyobj.BODY))
            {
                //First copy values of the given value into this object
                CopyValues(ephyobj);
                //Values are in, so decide which type of shape is needed to be loaded
                //We now have which type of object to load
                //These will create the textures, origins, bodies, and geoms
                switch (po_Object_Shape)
                {
                    case ObjectShape.Circle:
                        LoadasBall(components.Game.GraphicsDevice);
                        break;
                    case ObjectShape.Box:
                        LoadAsBox(components.Game.GraphicsDevice);
                        break;
                    case ObjectShape.FromTexture:
                        LoadAsTexture(components.Game.GraphicsDevice, components.ContentManager);
                        break;
                }
                _body.ConstructClone(ephyobj._body);
                //Created correct geom, so nwo copy values into it
                _geom.ConstructClone(_body, ephyobj._geom, Vector2.Zero, 0f, _isCreated);
                _sensorGeom.ConstructClone(_body, ephyobj._geom, Vector2.Zero, 0f, _isCreated);
                _body.Tag = this._id;
                _geom.Tag = this._id;
                _sensorGeom.Tag = this._id;
                
                _isCreated = true;
            }
            else if (ephyobj.PhyObjName != this.PhyObjName)
            {
                //The textures, origins, bodies and geoms are already created
                //Copy texture
                this._texture = ephyobj._texture;
                //Copy sensor texture
                this._sensorTexture = ephyobj._sensorTexture;
                //Copy origin
                this._origin = ephyobj._origin;
                //Copy sensor origin
                this._sensorOrigin = ephyobj._sensorOrigin;
                //Copy body and geoms
                
                    _body.ConstructClone(ephyobj._body);
                    //Created correct geom, so nwo copy values into it
                    _geom.ConstructClone(_body, ephyobj._geom, Vector2.Zero, 0f, _isCreated);
                    _sensorGeom.ConstructClone(_body, ephyobj._geom, Vector2.Zero, 0f, _isCreated);
            }  
             _body.ResetDynamics();
                       
            if (AddToPhysics)
            {
                AddToPhysicsSimulator();
                _body.Enabled = true;
                _geom.CollisionEnabled = true;
                if (_id.UnitID == UnitID.Tower && _isCreated)
                { int i; }
                if (IsSensorEnabled)
                    _sensorGeom.CollisionEnabled = true;
                else
                    _sensorGeom.CollisionEnabled = false;
            }
            else
            {
                _body.Enabled = false;
                _geom.CollisionEnabled = false;
                _sensorGeom.CollisionEnabled = false;
            }
            MoveDirection = direction;
            Position = location;
            MovementUpdateDelayTimer = 0;
            _originalSpawnLocation = location;
        }

        private void CopyValues(PhyObj phyObj)
        {
            this.PhyObjName = phyObj.PhyObjName;
            this.po_Object_Shape = phyObj.po_Object_Shape;
            this.po_TextureName = phyObj.po_TextureName;
            this.po_IColor = phyObj.po_IColor;
            this.po_BorderColor = phyObj.po_BorderColor;
            this.po_SensorColor = phyObj.po_SensorColor;
            this.po_SensorBorderColor = phyObj.po_SensorBorderColor;
            this.po_Radius = phyObj.po_Radius;
            this.po_SensorRadius = phyObj.po_SensorRadius;
            this.po_Width = phyObj.po_Width;
            this.po_Height = phyObj.po_Height;
            this.MovementUpdateDelay = phyObj.MovementUpdateDelay;
            this._isMoveByForce = phyObj._isMoveByForce;
            this.IsSensorEnabled = phyObj.IsSensorEnabled;
            this._moveSpeed = phyObj._moveSpeed;
        }

        private void CopyValues(Geom geom)
        {
            this._geom.InSimulation = geom.InSimulation;
            this._geom.CollidesWith = geom.CollidesWith;
            this._geom.CollisionCategories = geom.CollisionCategories;
            this._geom.CollisionResponseEnabled = geom.CollisionResponseEnabled;
            this._geom.FrictionCoefficient = geom.FrictionCoefficient;
            this._geom.RestitutionCoefficient = geom.RestitutionCoefficient;
            this._geom.CollisionGroup = geom.CollisionGroup;
            this._geom.CollisionEnabled = geom.CollisionEnabled;

            this._sensorGeom.InSimulation = geom.InSimulation;
            this._sensorGeom.CollidesWith = geom.CollidesWith;
            this._sensorGeom.CollisionCategories = geom.CollisionCategories;
            this._sensorGeom.CollisionResponseEnabled = geom.CollisionResponseEnabled;
            this._sensorGeom.FrictionCoefficient = geom.FrictionCoefficient;
            this._sensorGeom.RestitutionCoefficient = geom.RestitutionCoefficient;
            this._sensorGeom.CollisionGroup = geom.CollisionGroup;
            this._sensorGeom.CollisionEnabled = geom.CollisionEnabled;
        }

        private void CopyValues(Body body)
        {
            _body.Mass = body.Mass;
            _body.MomentOfInertia = body.MomentOfInertia;
            _body.IsStatic = body.IsStatic;
            _body.Position = body.Position;
            _body.Rotation = body.Rotation;
            _body.AngularVelocity = body.AngularVelocity;
            _body.Enabled = body.Enabled;
            _body.IgnoreGravity = body.IgnoreGravity;
            _body.IsQuadraticDragEnabled = body.IsQuadraticDragEnabled;
            _body.LinearDragCoefficient = body.LinearDragCoefficient;
            _body.LinearVelocity = body.LinearVelocity;
            _body.QuadraticDragCoefficient = body.QuadraticDragCoefficient;
            _body.RotationalDragCoefficient = body.RotationalDragCoefficient;
            _body.IdleTime = body.IdleTime;
            _body.IsAutoIdle = body.IsAutoIdle;
            _body.MinimumVelocity = body.MinimumVelocity;
        }

        /// <summary>
        /// Not used, but placed for conveince
        /// </summary>
        /// <param name="input"></param>
        public virtual void ReadContent(ContentReader input)
        {
           
            this.po_Object_Shape = input.ReadObject<ObjectShape>();
            this.po_TextureName = input.ReadString();
            this.po_IColor = input.ReadColor();
            this.po_BorderColor = input.ReadColor();
            this.po_SensorColor = input.ReadColor();
            this.po_SensorBorderColor = input.ReadColor();
            this.po_Radius = input.ReadInt32();
            this.po_SensorRadius = input.ReadInt32();
            this.po_Width = input.ReadInt32();
            this.po_Height = input.ReadInt32();
            this.MovementUpdateDelay = input.ReadDouble();
        }

        /// <summary>
        /// Physics object will remove itself from the physics simulation
        /// It will not remove itself from the object pool automatically. 
        /// This must be done manually from the objects manager (which should be the only class to call this function).
        /// </summary>
        public virtual void Remove(bool RemoveRefFromPhysics)
        {
            _body.Enabled = false;
            _geom.CollisionEnabled = false;
            _sensorGeom.CollisionEnabled = false;
            if (RemoveRefFromPhysics)
                this.RemoveRefFromPhysics();
        }
       
        private void RemoveRefFromPhysics()
        {
            if (IsRefInPhysics)
            {
                _physicsSimulator.Remove(this._body);
                _physicsSimulator.Remove(this._geom);
            }
            if(IsSensorRefInPhysics)
            _physicsSimulator.Remove(this._sensorGeom);
        }

        /// <summary>
        /// GET POSITION OF OBJECT
        /// </summary>
        /// 
        [ContentSerializerIgnore]
        public Vector2 Position
        {
            get { return _body.Position; }
            set { _body.Position = value; }
        }

        #endregion

        #region Loading

        /// <summary>
        /// 
        /// </summary>
        /// <param name="graphicsDevice"></param>
        private void LoadasBall(GraphicsDevice graphicsDevice)
        {
            //CREATE CIRCLE TEXTURE
            _texture = DrawingSystem.DrawingHelper.CreateCircleTexture(graphicsDevice, po_Radius, po_IColor, po_BorderColor);

            //CREATE Circle SENSOR TEXTURE
            _sensorTexture = DrawingSystem.DrawingHelper.CreateCircleTexture(graphicsDevice, po_SensorRadius, po_SensorColor, po_SensorBorderColor);
            //SET ORIGIN
            _origin = new Vector2(_texture.Width / 2f, _texture.Height / 2f);
            _sensorOrigin = new Vector2(_sensorTexture.Width / 2f, _sensorTexture.Height / 2f);
            //CREATE Circle BODY
            _body = BodyFactory.Instance.CreateCircleBody(po_Radius, 1f);

            //CREATE Circle GEOM
            _geom = GeomFactory.Instance.CreateCircleGeom(_body, po_Radius, 20, 0f);

            //CREATE Circle SENSOR GEOM
            //if(presetGeom.IsSensor)
            _sensorGeom = GeomFactory.Instance.CreateCircleGeom(_body, po_SensorRadius, 20);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="graphicsDevice"></param>
        private void LoadAsBox(GraphicsDevice graphicsDevice)
        {
            if (_body != null && _geom != null && _sensorGeom != null)
            {
                DeletePreviousInstance(_physicsSimulator, _body, _geom);
                _body.ResetDynamics();
            }

            //CREATE RECTANGLE TEXTURE
            _texture = DrawingSystem.DrawingHelper.CreateRectangleTexture(graphicsDevice, po_Width, po_Height, po_IColor, po_BorderColor);

            //CREATE SENSOR TEXTURE
            _sensorTexture = DrawingSystem.DrawingHelper.CreateCircleTexture(graphicsDevice, po_SensorRadius, po_SensorColor, po_SensorBorderColor);
            //SET ORIGIN
            _origin = new Vector2(_texture.Width / 2f, _texture.Height / 2f);

            _sensorOrigin = new Vector2(_sensorTexture.Width / 2f, _sensorTexture.Height / 2f);
            
            //CREATE BODY
            _body = BodyFactory.Instance.CreateRectangleBody(po_Width, po_Height, 1f);

            //CREATE GEOM
            _geom = GeomFactory.Instance.CreateRectangleGeom(_body, po_Width, po_Height, 0);

            //CREATE SENSOR GEOM
            _sensorGeom = GeomFactory.Instance.CreateCircleGeom(_body, po_SensorRadius, 14);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="graphicsDevice"></param>
        /// <param name="content"></param>
        private void LoadAsTexture(GraphicsDevice graphicsDevice, ContentManager content)
        {            
            _texture = content.Load<Texture2D>(po_TextureName);
           
            //MAKE SURE TEXTURE ISN'T NULL
            if (_texture == null)
                throw new Exception("MUST PASS IN VALID TEXTURE");
            if (_body != null && _geom != null && _sensorGeom != null)
            {
                DeletePreviousInstance(_physicsSimulator, _body, _geom);
                _body.ResetDynamics();
            }

            //CREATE SENSOR TEXTURE
            _sensorTexture = DrawingSystem.DrawingHelper.CreateCircleTexture(graphicsDevice, po_SensorRadius, po_SensorColor, po_BorderColor);

            ////Create an array to hold the data from the texture
            //uint[] data = new uint[_texture.Width * _texture.Height];

            ////Transfer the texture data to the array
            //_texture.GetData(data);

            ////Calculate the vertices from the array
            
            //PolygonCreationAssistance pca = new PolygonCreationAssistance(data, _texture.Width, _texture.Height);
            //Vertices.CreatePolygon(ref pca);
            //pca.HullTolerance = 1.2f;
            //pca.HoleDetection = false;
            //pca.MultipartDetection = false;
            //pca.AlphaTolerance = 20;
            _sensorOrigin = new Vector2(_sensorTexture.Width / 2f, _sensorTexture.Height / 2f);
            //SET ORIGIN
            //List<Vertices> verts = Vertices.CreatePolygon(ref pca);
            //verts[0].Reverse();
            _origin = new Vector2(this._texture.Width / 2, this._texture.Height / 2);
            //CREATE BODY
            _body = BodyFactory.Instance.CreateRectangleBody(_texture.Width, _texture.Height, 1f);
            
            //CREATE GEOM
            _geom = GeomFactory.Instance.CreateRectangleGeom(this._body, _texture.Width, _texture.Height);

            //CREATE SENSOR GEOM
            _sensorGeom = GeomFactory.Instance.CreateCircleGeom(_body, po_SensorRadius, 14);
            
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="physicsSimulator"></param>
        /// <param name="body"></param>
        /// <param name="geom"></param>
        private void DeletePreviousInstance(PhysicsSimulator physicsSimulator, Body body, Geom geom)
        {
            physicsSimulator.Remove(body);
            physicsSimulator.Remove(geom);
        }

        /// <summary>
        /// Add this physics object to the physics simulator
        /// </summary>
        private void AddToPhysicsSimulator()
        {
            _physicsSimulator.Add(this._body);
            _physicsSimulator.Add(this._geom);
            IsRefInPhysics = true;
            if (_sensorGeom != null)
            { _physicsSimulator.Add(this._sensorGeom); IsSensorRefInPhysics = true; }
        }

        
        #endregion       
    }
}